import ilog.concert.*;
import ilog.cplex.*;
import ilog.concert.IloException;
import ilog.concert.IloLinearNumExpr;
import ilog.concert.IloNumVar;
import ilog.concert.IloObjective;
import ilog.concert.IloRange;
import ilog.cplex.IloCplex;

import java.util.Arrays;
import java.util.ArrayList;



public class subproblem extends IloCplex{
	
	int u; 			//upper bound of day in a row
	int l; 			//lower bound of days in a row
	int t;			//nuimber of time periods 
	
	public IloObjective reducedCosts;
	
	public static ArrayList<String> id = new ArrayList<String>(); //muss aus masterproblem kommen/gespeicher werden!!!!
	
	
	IloCplex sp;
	IloNumVar[] x;
	
	public double[] solve () throws IloException{
		this.sp = new IloCplex();
		sp.setParam(IloCplex.BooleanParam.NumericalEmphasis, true);
		this.x = new IloNumVar[t];
		
		for(int i = 0; i< t; i++){
			x[i] = sp.numVar(0,1, IloNumVarType.Bool);
		}
		
		
		//----------------OBF----------------
		
		IloLinearNumExpr objfunc = sp.linearNumExpr();
		for(int i = 0; i < t; i++){
			objfunc.addTerm(1.0, x[i]);
		}
		
		sp.addMinimize(objfunc);
		
		
		IloLinearNumExpr st = sp.linearNumExpr();
		
		
		//----------------CS1---------------- 
		//assures that only one shift can be chosen per day
		for(int k = 0; k < 7; k++){
			st.clear();
			for(int i = 0; i < 3; i++){
				st.addTerm(1.0, x[i + 3*k]);
			}	
			sp.addLe(st, 1);
		}
		
		//----------------CSXX---------------- 
		//sets the number of workdays per week
		st.clear();
		for(int i = 0; i < t; i++){
			st.addTerm(1.0, x[i]);
		}		
		sp.addEq(st, 6);
				
		
		
		//----------------CS2---------------- 
		// makes sure that the there is a minimum of consecutive shifts which >= l
		for(int p = 0; p < (7-(l+1)); p++){
			st.clear();
			for(int i = 0; i < (l+1)*3; i++){
				st.addTerm(1.0, x[i + 3*p]);
			}
			sp.addGe(st, l);
		}
		
		
		//----------------CS3---------------- 
		// makes sure that the there is a maximum of consecutive shifts which is <= u
		for(int m = 0; m < (7-(u+1)); m++){
			st.clear();
			for(int i = 0; i < (u+1)*3; i++){
				st.addTerm(1.0, x[i + 3*m]);
			}
			sp.addLe(st, u);
		}
		
		
		//----------------CS4----------------
		//assures that no unpermitted tour follows another tour
		for(int k = 0; k < 6; k++){
			st.clear();
			st.addTerm(1.0,x[3*k+1]);
			st.addTerm(1.0, x[3*(k+1)]);
			sp.addLe(st, 1);
		}
		
		//----------------CS5---------------- 
		//assures that no unpermitted tour follows another tour
		for(int k = 0; k < 6; k++){
			st.clear();
			st.addTerm(1.0,x[3*k+2]);
			st.addTerm(1.0, x[3*(k+1)]);
			sp.addLe(st, 1);
		}
		
		//----------------CS6---------------- 
		//assures that no unpermitted tour follows another tour
		for(int k = 0; k < 6; k++){
			st.clear();
			st.addTerm(1.0,x[3*k+2]);	 
			st.addTerm(1.0, x[3*(k+1)+1]);
			sp.addLe(st, 1);
		}
		
		sp.solve();
		
		System.out.println(Arrays.toString(sp.getValues(x)));
		
		return sp.getValues(x);
		
	}
		
	
	public subproblem(int u, int l, int t){
		this.u = u;
		this.l = l;
		this.t = t;
	}

	public static void main(String[] args) {
		int u = 4; 			//upper bound of day in a row
		int l = 3; 			//lower bound of days in a row
		int t = 21;			//nuimber of time periods 
		
				
		double[] solution;
		
		
		subproblem s= new subproblem(u, l, t);
		try{
			solution = s.solve();
		} catch (IloException e){
			e.printStackTrace();
            System.err.println("Concert exception caught: " + e);
		}

	}
	
	public void setObjective(masterproblem master) throws IloException {
		reducedCosts.clearExpr();
		IloLinearNumExpr expression = linearNumExpr();

		// yu - is constant over the iterations
		for (Yu[] yu1 : yu) {
		    for (Yu yu : yu1) {
			expression.addTerm(GlobalValues.puk[yu.k], yu.y);
		    }
		}

		// x - not constant
		for (X[][] x2 : x) {
		    for (X[] x1 : x2) {
			for (X x : x1) {
			    double coefficientX = master.getReducedCostCoefficientForX(x.c, x.i, x.w, x.tau);
			    if (coefficientX < 0.0) {
				expression.addTerm(coefficientX, x.x);
			    }
			}
		    }
		}

		// 3rd term: convexity dual (constant for each circulation)
		expression.setConstant(master.getReducedCostCoefficientForConvexity(carousel));
		reducedCosts.setExpr(expression);
	    }

}
